#include "usart.h"
#include "nvic.h"

/**
 * @brief       串口X初始化函数
 * @param       sclk: 串口X的时钟源频率(单位: MHz)
 *              A9-----TX
 *              A10----RX
 * @note        注意: 必须设置正确的sclk, 否则串口波特率就会设置异常.
 * @param       baudrate: 波特率, 根据自己需要设置波特率值
 * @retval      无
 */
void usart_init(uint32_t sclk, uint32_t baudrate) {
    uint32_t temp;
    /* IO 及 时钟配置 */
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* 使能串口IO引脚时钟 */
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN; /* 使能串口时钟 */
    /* 串口IO引脚 模式设置 */
    GPIOA->MODER &= ~(GPIO_MODER_MODER9_Msk|GPIO_MODER_MODER10_Msk);
    GPIOA->MODER |= (GPIO_MODER_MODER9_1|GPIO_MODER_MODER10_1);
    GPIOA->OTYPER &= ~(GPIO_OTYPER_OT_9|GPIO_OTYPER_OT_10);
    GPIOA->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEEDR9_Msk|GPIO_OSPEEDR_OSPEEDR10_Msk);
    GPIOA->OSPEEDR |= (GPIO_OSPEEDR_OSPEEDR9_0|GPIO_OSPEEDR_OSPEEDR9_1|GPIO_OSPEEDR_OSPEEDR10_0|GPIO_OSPEEDR_OSPEEDR10_1);
    GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR9_Msk|GPIO_PUPDR_PUPDR10_Msk);
    GPIOA->PUPDR |= (GPIO_PUPDR_PUPDR9_0|GPIO_PUPDR_PUPDR10_0);
    /* 复用功能选择 AF1 */
    GPIOA->AFR[1] &= ~(GPIO_AFRH_AFRH1|GPIO_AFRH_AFRH2);
    GPIOA->AFR[1] |= (1<<4)|(1<<8);

    temp = (sclk * 1000000 + baudrate / 2) / baudrate;              /* 得到USARTDIV@OVER8 = 0, 采用四舍五入计算 */
    /* 波特率设置 */
    USART_UX->BRR = temp;       /* 波特率设置@OVER8 = 0 */
    USART_UX->CR1 = 0;
    USART_UX->CR1 |= USART_CR1_TE;
#if USART_EN_RX     /* 如果使能了接收 */
    USART_UX->CR1 |=USART_CR1_RE;
    USART_UX->CR1 |= USART_CR1_RXNEIE; /* 接收中断 */
    sys_nvic_init(3, 3, USART_UX_IRQn, 2); /* 组2，最低优先级 */
#endif
    USART_UX->CR1 |= USART_CR1_UE;
}

#if USART_EN_RX     /* 如果使能了接收 */
/* 接收缓冲, 最大USART_REC_LEN个字节. */
uint8_t g_usart_rx_buf[USART_REC_LEN];
/*  接收状态
 *  bit15，      接收完成标志
 *  bit14，      接收到0x0d
 *  bit13~0，    接收到的有效字节数目
*/
uint8_t g_usart_rx_sta = 0;
/**
 * @brief       串口X中断服务函数
 * @param       无
 * @retval      无
 */
void USART_UX_IRQHandler(void) {
    uint8_t rxdata;
    if (USART_UX->ISR & (1 << 5)) {               /* 接收到数据 */
        rxdata = USART_UX->RDR;
        g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = rxdata;   /* 存储数据到 g_usart_rx_buf */
        g_usart_rx_sta++;
        if (g_usart_rx_sta > (USART_REC_LEN - 1))g_usart_rx_sta = 0;/* 接收数据溢出, 重新开始接收 */
    }
}
#endif
